//
//  YHRequest.m
//  MoreCoin
//
//  Created by 林宁宁 on 2019/10/17.
//  Copyright © 2019 MoreCoin. All rights reserved.
//

#import "YHRequest.h"

#import <YYModel/NSObject+YYModel.h>
#import <AFNetworking/AFSecurityPolicy.h>
#import <AFNetworking/AFURLRequestSerialization.h>

#import "YHApp.h"
#import "YHConstant+Null.h"
#import "YHRequestResponse.h"

#import <objc/runtime.h>

@interface YHRequest()

@property (copy, nonatomic) void(^successBlock)(NSString * _Nullable message, id result);
@property (copy, nonatomic) void(^failBlock)(NSString * _Nullable failureMsg, NSInteger errorCode, NSError * error);

@property (retain, nonatomic, readwrite) YHRequestConfig * config;

@end

@implementation YHRequest


+(void)load{

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        
//        [YTKNetworkConfig sharedConfig].securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];
        
//        [YTKNetworkConfig sharedConfig].securityPolicy.allowInvalidCertificates = NO;
//        [YTKNetworkConfig sharedConfig].securityPolicy.validatesDomainName = NO;
        
#ifndef DEBUG
        NSURLSessionConfiguration * conf = [YTKNetworkConfig sharedConfig].sessionConfiguration;
        conf.connectionProxyDictionary = @{};
#endif
    });
}

-(instancetype)init{
    self = [super init];
    if(self){
        NSAssert([YHApp manager].mediator.http, @"请先设置http的mediator");
        
        YHRequestConfig * config = [YHRequestConfig new];
        self.config = config;
        self.config.method = YTKRequestMethodPOST;
        self.config.baseURL = [YHApp manager].mediator.http.http_defaultDomain;
        self.config.pathURL = @"";
        self.config.timeout = 10;
        self.config.showLoading = NO;
    }
    return self;
}

+ (YHRequest<id> *)instanceConfig:(void (^_Nonnull)(YHRequest * _Nonnull request, YHRequestConfig * _Nonnull config))configBlock{
    YHRequest * request = [[self class] new];
    if(configBlock){
        configBlock(request,request.config);
    }
    return request;
}

#pragma mark - Override

-(NSString *)baseUrl{
    return NullShow(self.config.baseURL);
}

-(NSString *)requestUrl{
    NSMutableString * path = [NSMutableString new];
    if(IsNonNull(self.config.pathURL)){
        if(![self.config.pathURL hasPrefix:@"/"]){
            [path appendString:@"/"];
        }
        [path appendString:self.config.pathURL];
    }
    return path;
}

-(YTKRequestSerializerType)requestSerializerType{
    return self.config.requestSerializerType;
}

-(YTKResponseSerializerType)responseSerializerType{
    return self.config.responseSerializerType;
}

- (YTKRequestMethod)requestMethod{
    return self.config.method;
}

-(NSTimeInterval)requestTimeoutInterval{
    return self.config.timeout;
}

-(id)requestArgument{
    if (self.config.argument){
        NSDictionary * dicModel = self.config.argument;
        if(![self.config.argument isKindOfClass:[NSArray class]] &&
           ![self.config.argument isKindOfClass:[NSDictionary class]]){
            id jsonObj = [self.config.argument yy_modelToJSONObject];
            if(jsonObj){
                dicModel = jsonObj;
            }
        }
        if([dicModel isKindOfClass:[NSDictionary class]]){
            if([[YHApp manager].mediator.http respondsToSelector:@selector(http_parameterEncryption:)]){
                return [[YHApp manager].mediator.http http_parameterEncryption:dicModel];
            }
        }
        return dicModel;
    }
    return nil;
}

// 上传文件信息
-(AFConstructingBlock)constructingBodyBlock{
    if(IsEmpty(self.config.uploadFileBeans)){
        return nil;
    }
    AFConstructingBlock block = ^(id<AFMultipartFormData> formData){
        NSString *(^fileTypeValue)(NSData * data) = ^ NSString *(NSData *data){
            uint8_t c;
            [data getBytes:&c length:1];
            switch (c) {
                case 0xFF:
                    return @"image/jpeg";
                case 0x89:
                    return @"image/jpeg";
                case 0x47:
                    return @"image/gif";
                default:
                    return @"image/png";
                    return nil;
            }
        };
         
        for(YHRequestUploaBean * bean in self.config.uploadFileBeans){
            if (IsNull(bean.fileType)) {
                if (IsNonNull(bean.filePath)) {
                    bean.fileType = [bean.filePath hasSuffix:@"png"]?@"image/jpeg":bean.fileType;
                    bean.fileType = [bean.filePath hasSuffix:@"jpeg"]?@"image/jpeg":bean.fileType;
                    bean.fileType = [bean.filePath hasSuffix:@"jpg"]?@"image/jpeg":bean.fileType;
                    bean.fileType = [bean.filePath hasSuffix:@"jpe"]?@"image/jpeg":bean.fileType;
                    bean.fileType = [bean.filePath hasSuffix:@"gif"]?@"image/gif":bean.fileType;
                    bean.fileType = [bean.filePath hasSuffix:@"amr"]?@"audio/AMR":bean.fileType;
                    if (IsEmpty(bean.fileType)) {
                        bean.fileType = fileTypeValue([NSData dataWithContentsOfFile:bean.filePath]);
                    }
                }else if (IsNotEmpty(bean.fileData)){
                    bean.fileType = fileTypeValue(bean.fileData);
                }else if (bean.fileImage){
                    bean.fileType = @"image/jpeg";
                }
            }
         
            if(IsNotEmpty(bean.fileData)){
                [formData appendPartWithFileData:bean.fileData
                                            name:@"files"
                                        fileName:bean.fileNameUpload
                                        mimeType:bean.fileType];
            }else if (IsNonNull(bean.filePath)){
                [formData appendPartWithFileURL:[NSURL fileURLWithPath:bean.filePath]
                                           name:@"files"
                                       fileName:bean.fileNameUpload
                                       mimeType:bean.fileType
                                          error:nil];
            }else if (IsNonNull(bean.fileImage)){
                [formData appendPartWithFileData:UIImageJPEGRepresentation(bean.fileImage, 1)
                                            name:@"files"
                                        fileName:bean.fileNameUpload
                                        mimeType:bean.fileType];
            }
        }
    };
    if (self.config.argument){
        NSDictionary * dicModel = self.config.argument;
        if(![self.config.argument isKindOfClass:[NSArray class]] &&
           ![self.config.argument isKindOfClass:[NSDictionary class]]){
            id jsonObj = [self.config.argument yy_modelToJSONObject];
            if(jsonObj){
                dicModel = jsonObj;
            }
        }
        if([dicModel isKindOfClass:[NSDictionary class]]){
            if([[YHApp manager].mediator.http respondsToSelector:@selector(http_fileUploadParameterEncryption:)]){
                self.config.argument = [[YHApp manager].mediator.http http_fileUploadParameterEncryption:dicModel];
            }
        }
    }
    return block;
}

//// 所有成功的code都返回未 success
//- (BOOL)statusCodeValidator {
//    if(self.error){
//        return [super statusCodeValidator];
//    }
//    return YES;
//}

-(NSDictionary<NSString *,NSString *> *)requestHeaderFieldValueDictionary{
    NSMutableDictionary * headerFieldDic = [NSMutableDictionary new];
    [headerFieldDic addEntriesFromDictionary:[YHApp manager].mediator.http.http_requestHeaderFieldValuePublic];
    if (self.config.requestSerializerType == YTKRequestSerializerTypeHTTP) {
        headerFieldDic[@"Content-Type"] = @"application/x-www-form-urlencoded";
    }
    if(self.config.customHeaderField && [self.config.customHeaderField isKindOfClass:[NSDictionary class]]){
        [headerFieldDic addEntriesFromDictionary:self.config.customHeaderField];
    }
    if([[YHApp manager].mediator.http respondsToSelector:@selector(http_requestHeaderParameterEncryption:)]){
        return [[YHApp manager].mediator.http http_requestHeaderParameterEncryption:headerFieldDic];
    }
    return headerFieldDic;
}


#pragma mark - execute

-(void)execute{
    [self executeWithSuccess:nil failure:nil];
}
- (void)executeWithSuccess:(void (^)(NSString * _Nullable, id _Nonnull))success{
    [self executeWithSuccess:success failure:nil];
}

-(void)executeWithSuccess:(void (^)(NSString * _Nullable, id _Nonnull))success
                  failure:(void (^)(NSString * _Nullable, NSInteger, NSError * _Nonnull))failure{
    self.successBlock = success;
    self.failBlock = failure;
    
    [self startRequest];
}

/// 开始请求
- (void)startRequest{
    WS(weakSelf)
    if([[YHApp manager].mediator.http respondsToSelector:@selector(http_requestStart:)]){
        [[YHApp manager].mediator.http http_requestStart:self];
    }
    void(^failureBlock)(YHRequestResponse * _Nullable, YTKBaseRequest *) = ^void(YHRequestResponse * _Nullable response, YTKBaseRequest * request) {
        if([[YHApp manager].mediator.http respondsToSelector:@selector(http_requestEnd:)]){
            [[YHApp manager].mediator.http http_requestEnd:weakSelf];
        }
        if([[YHApp manager].mediator.http respondsToSelector:@selector(http_requestFail:response:)]){
            [[YHApp manager].mediator.http http_requestFail:weakSelf response:response];
        }
        NSInteger errorCode = (NSInteger)request.error.code;
        [[YHApp manager].mediator.http http_handleErrorCode:response.code responseStatusCode:errorCode message:response.message request:weakSelf];
        if(response.code != 0){
            errorCode = response.code;
        }
        if(weakSelf.failBlock){
            weakSelf.failBlock(response.message,errorCode,request.error);
        }
//        YHRequestLog(@"\n\n ❌ HTTP\
//                     \n requestFail:%@\
//                     \n argument:%@\
//                     \n method:%@\
//                     \n message:%@\
//                     \n requestCode:%zd\
//                     \n dataCode:%zd\
//                     \n error:%@\
//                     \n responseData:%@\
//                     \n",
//                     request.originalRequest.URL,
//                     request.requestArgument,
//                     request.originalRequest.HTTPMethod,
//                     response.message,
//                     request.response.statusCode,
//                     response.code,
//                     request.error,
//                     response.responseData);
        
    };
    
    void(^successBlock)(YHRequestResponse * , YTKBaseRequest * ) = ^void(YHRequestResponse * _Nullable response, YTKBaseRequest * request){
        if([[YHApp manager].mediator.http respondsToSelector:@selector(http_requestEnd:)]){
            [[YHApp manager].mediator.http http_requestEnd:weakSelf];
        }
        if([[YHApp manager].mediator.http respondsToSelector:@selector(http_requestSuccess:response:)]){
            [[YHApp manager].mediator.http http_requestSuccess:weakSelf response:response];
        }
        if([[YHApp manager].mediator.http respondsToSelector:@selector(http_HUDSuccessMessage:)]){
            [[YHApp manager].mediator.http http_HUDSuccessMessage:response.message];
        }
        
        
        if(weakSelf.config.responseClass){
            id resultObj = [weakSelf.config.responseClass yy_modelWithJSON:response.result];
            if ([response.result isKindOfClass:[NSArray class]]){
                resultObj = [NSArray yy_modelArrayWithClass:weakSelf.config.responseClass json:response.result];
                weakSelf.successBlock(response.message,resultObj);
            }else if(resultObj){
                weakSelf.successBlock(response.message,resultObj);
            }else if (IsNull(response.result)){
                weakSelf.successBlock(response.message,resultObj);
            }else {
                if(weakSelf.failBlock){
                    weakSelf.failBlock(response.message,0,[NSError new]);
                }
            }
        }else{
            if(weakSelf.successBlock){
                weakSelf.successBlock(response.message,response.result);
            }
        }
        
//        YHRequestLog(@"\n\n ✅ HTTP \
//                     \n requestResponse:%@\n \
//                     \n method:%@\
//                     \n argument:%@\
//                     \n result—part:\n",
//                     request.originalRequest.URL,
//                     request.originalRequest.HTTPMethod,
//                     request.requestArgument);
    };
    
//    YHRequestLog(@"\n\n 🌱 HTTP\
//                 \n requestSend:  \
//                 \n baseurl: %@ \
//                 \n url:%@\
//                 \n argument:%@\
//                 \n Headers:%@\
//                 \n method:%d\n",
//                 self.baseUrl,
//                 self.requestUrl,
//                 self.requestArgument,
//                 self.responseHeaders,
//                 self.requestMethod
//                 );
    
    [self startWithCompletionBlockWithSuccess:^(__kindof YTKBaseRequest * _Nonnull request) {
        NSError *error;
        id dict = [NSJSONSerialization JSONObjectWithData:request.responseData options:0 error:&error];
        if(request.responseData && request.responseData.length == 0){
            //数据返回是空
            dict = @{};
            error = nil;
        }
        if (error) {
            //数据转化异常
            NSString * responseString = [[NSString alloc] initWithData:request.responseData encoding:(NSUTF8StringEncoding)];
            dict = responseString;
//            NSLog(@" \n>>>>>>>> ========= 数据解析异常: %@",responseString);
        }
        if(!dict){
            YHRequestResponse * response = [YHRequestResponse new];
            response.message = @"数据异常";
            response.code = -1;
            failureBlock(response, request);
            return;
        }
        YHRequestResponse * response = [YHRequestResponse yy_modelWithDictionary:dict];
        response.responseCode = request.response.statusCode;
        response.responseData = dict;
        
        if([[YHApp manager].mediator.http respondsToSelector:@selector(http_requestIsSuccessWithResponseCode:)]){
            BOOL isSuccess = [[YHApp manager].mediator.http http_requestIsSuccessWithResponseCode:response.code];
            if(isSuccess){
                successBlock(response, request);
            }else{
                failureBlock(response, request);
            }
        }else{
            if (response.responseCode >= 200 &&
                response.responseCode < 300){
                successBlock(response, request);
            }else{
                failureBlock(response, request);
            }
        }
    } failure:^(__kindof YTKBaseRequest * _Nonnull request) {
        YHRequestResponse * response = [YHRequestResponse new];
        response.code = request.responseStatusCode;
        failureBlock(response, request);
    }];
}

@end
